package com.new2i.util;

import java.math.BigDecimal;import java.util.ArrayList;
import java.util.Enumeration;import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.new2i.database.Database;
import com.new2i.database.SqlCustomUtils;

/**
 * 分页对象,
 * 
 * @author liyuhong
 *
 *         如果是MYSQL数据库，在传入的SQL中的有 MYSQL_LIMIT_POS
 *         字符串，这将不采用通用的分页sql，将替换MYSQL_LIMIT_POS为(limit 起始位置,本页记录数)
 */
public class Pagination {
	// public static final Pagination2 EMPTY_PAGE = new Pagination2();
	final int DEFAULT_PAGE_SIZE = 20;
	// public static final int MAX_PAGE_SIZE = 9999;

	private int PAGE_SIZE = DEFAULT_PAGE_SIZE; // 每页显示记录数

	private String DB_TYPE = "mysql";// 数据库类型

	private Class<?> CLASS_OBJ = null;// 数据对象

	private long TOTAL_PAGE_COUNT; // 总页数

	private long TOTAL_RECORDS_COUNT = 0;// 总记录数

	Database database;// 数据库对象

	String STR_SQL;// 原SQL

	String TOTAL_SQL;// 合计sql

	String PAGE_SQL;// 分页sql

	String HTML_NAV;// 导航HTML字符串

	String PARAMS_STR;// 参数字串

	String paramsEncode = "utf8";// 参数页面的字符集编码，默认utf8

	private long CURRENT_PAGE_NO = 1;// 当前页码

	HttpServletRequest thisRequest;// 页面请求对象
	// -------------------------------------------------------------------

	/**
	 * 构造函数
	 * 
	 * @param sql
	 *            sql语句
	 * @param db
	 *            数据库对象
	 * @param currentPageNo
	 *            当前页号,可设置为null
	 * @param everyPageRecordCount
	 *            每页记录数
	 * @param classObj
	 *            返回数据结果的类
	 * @param db_type
	 *            数据库类型
	 * @param request
	 *            HttpServletRequest对象
	 */
	public Pagination(String sql, Database db, String currentPageNo, String everyPageRecordCount, Class<?> classObj,
			String db_type, HttpServletRequest request) {

		STR_SQL = sql;// 原SQ

		database = db;

		// 设置数据类型
		if (db_type != null)
			this.DB_TYPE = db_type;

		// 设置页码
		if (request.getParameter("pageno") != null) {
			try {
				CURRENT_PAGE_NO = new Integer(request.getParameter("pageno"));
			} catch (NumberFormatException e) {

			}
		}

		// if(currentPageNo!=null) CURRENT_PAGE_NO=new Integer(currentPageNo);

		if (everyPageRecordCount != null)
			PAGE_SIZE = new Integer(everyPageRecordCount);// 每页显示记录数

		generateSQL();// 根据数据库类型产生合计sql和分页sql

		records();// 获得总记录数

		pageCount();// 计算总页数

		CLASS_OBJ = classObj;

		thisRequest = request;

	}

	/**
	 * 
	 * @param sql
	 *            sql语句
	 * @param db
	 *            Database对象
	 * @param currentPageNo
	 *            当前页号，可以设置null
	 * @param everyPageRecordCount
	 *            每页记录条数
	 * @param classObj
	 *            数据对象
	 * @param request
	 */
	public Pagination(String sql, Database db, String currentPageNo, String everyPageRecordCount, Class<?> classObj,
			HttpServletRequest request) {
		this(sql, db, currentPageNo, everyPageRecordCount, classObj, null, request);
	}

	/**
	 * 
	 * @param sql
	 *            sql语句
	 * @param db
	 *            Database对象
	 * @param currentPageNo
	 *            当前页号，可以设置null
	 * @param everyPageRecordCount
	 *            每页记录条数
	 * @param request
	 */
	public Pagination(String sql, Database db, String currentPageNo, String everyPageRecordCount,
			HttpServletRequest request) {
		this(sql, db, currentPageNo, everyPageRecordCount, null, null, request);
	}

	/**
	 * 设置传递参数中的字符集编码
	 * 
	 * @param paramsEncode
	 *            字符集编码 ，默认是utf8
	 */
	public void setParamsEncode(String paramsEncode) {
		this.paramsEncode = paramsEncode;
	}

	/**
	 * 获得总记录数
	 */
	@SuppressWarnings("unchecked")
	private void records() {

		Map<String, Object> mpCount = (Map<String, Object>) database.query(TOTAL_SQL, 0);

		if (mpCount != null && !mpCount.isEmpty() && mpCount.get("count(*)") != null) {

			if (DB_TYPE.toLowerCase().equals("oracle"))
				TOTAL_RECORDS_COUNT = ((BigDecimal) mpCount.get("count(*)")).intValue();

			if (DB_TYPE.toLowerCase().equals("mysql"))
				TOTAL_RECORDS_COUNT = ((Long) mpCount.get("count(*)")).intValue();// 总记录数
		}

	}

	/**
	 * 根据数据库类型产生合计sql和分页sql
	 */
	private void generateSQL() {

		// ==== ORACLE ====//
		if (DB_TYPE.toLowerCase().equals("oracle")) {

			TOTAL_SQL = "select count(*) from (" + STR_SQL + ")";

			PAGE_SQL = "select * from " + "(select a.* ,rownum rownumber " + "from ( " + STR_SQL + " ) a ) "
					+ "where  rownumber>=? and rownumber<=?";
		}

		// ==== MYSQL ====//
		if (DB_TYPE.toLowerCase().equals("mysql")) {

			if (STR_SQL.indexOf("MYSQL_LIMIT_POS") < 0) { // 在sql中找不到特殊标识MYSQL_LIMIT_POS，则采用通用SQL
				PAGE_SQL = "select * from (" + STR_SQL + ") t limit ?," + PAGE_SIZE + " ";
				TOTAL_SQL = "select count(*) from (" + STR_SQL + ") t";
			} else {
				PAGE_SQL = STR_SQL;
				TOTAL_SQL = "select count(*) from (" + STR_SQL.replaceFirst("MYSQL_LIMIT_POS", "") + ") t";
			}
			// PAGE_SQL="select * from ("+STR_SQL+") t limit ?,"+PAGE_SIZE+" ";
		}
	}

	/**
	 * 计算总页数
	 */
	private void pageCount() {
		TOTAL_PAGE_COUNT = Math.round(Math.ceil(new Double(TOTAL_RECORDS_COUNT).doubleValue() / PAGE_SIZE));// 总页数
	}

	/**
	 * 获取数据
	 * 
	 * @return
	 */
	public List<?> getData() {

		// 根据当前页码获得在数据库中起始位置

		if (CURRENT_PAGE_NO > TOTAL_PAGE_COUNT)
			CURRENT_PAGE_NO = TOTAL_PAGE_COUNT;

		if (CURRENT_PAGE_NO < 1)
			CURRENT_PAGE_NO = 1;

		long startPos = (CURRENT_PAGE_NO - 1) * PAGE_SIZE;// 数据库起始位置

		long endPos = startPos + PAGE_SIZE - 1;// 数据库结束位置

		List<?> lt = new ArrayList<>();

		String thisPageSql = null;

		if (this.DB_TYPE.toLowerCase().equals("mysql") && PAGE_SQL.indexOf("MYSQL_LIMIT_POS") >= 0) {

			thisPageSql = PAGE_SQL.replaceFirst("MYSQL_LIMIT_POS", "limit " + startPos + "," + PAGE_SIZE);

		} else {

			thisPageSql = SqlCustomUtils.insertVal(PAGE_SQL,
					new String[] { String.valueOf(startPos), String.valueOf(endPos) });
		}
		if (CLASS_OBJ == null) {
			// 返回List<?><Map>类型
			lt = (List<?>) database.query(thisPageSql, null, 1, null);
		} else {
			// 返回List<?><Bean>类型
			lt = (List<?>) database.query(thisPageSql, null, 20, CLASS_OBJ);
		}

		return lt;
	}

	/**
	 * 获得导航html字符串,必须结合 jquery代码
	 * 
	 * @return
	 */
	public String getHtmlNav() {
		/*
		 * 导航样式 <a href="#">&lt;&lt;</a> <a href="#">1</a> <a href="#">2</a> <a
		 * href="#">3</a> <a href="#">4</a> <a href="#">5</a> <a href="#">6</a>
		 * <a href="#">7</a> <a href="#">18</a> <a style=
		 * "padding: 0px 4px; width: auto;" href="#">下一页</a>
		 */

		if (TOTAL_PAGE_COUNT <= 1)
			return "";

		// 根据当前页码，计算出导航字符串,每8个页面为一个显示，当前页码处于哪个页面序列中

		int everyRecCount = 8;// 没页面序列的页面数

		// 获得总共页码序列数
//		long serialCount = Math.round(Math.ceil(new Double(TOTAL_PAGE_COUNT).doubleValue() / everyRecCount));

		// 当前页面所处页码序列位置
		long currentSerialNo = Math.round(Math.ceil(new Double(CURRENT_PAGE_NO).doubleValue() / everyRecCount));

		long start = (currentSerialNo - 1) * everyRecCount + 1;// 起始位置

		long end = start + everyRecCount - 1;// 结束位置

		long prepage = ((CURRENT_PAGE_NO - 1) < 1 ? 1 : CURRENT_PAGE_NO - 1);// 上一页

		long nextpage = (CURRENT_PAGE_NO + 1) > TOTAL_PAGE_COUNT ? TOTAL_PAGE_COUNT : CURRENT_PAGE_NO + 1;// 下一页

		if (end > TOTAL_PAGE_COUNT)
			end = TOTAL_PAGE_COUNT;

		PARAMS_STR = this.createParamsHref(this.thisRequest);

		StringBuffer sbHtml = new StringBuffer();

		sbHtml.append("<span class='page-nav'>");
		// sbHtml.append("<span class=\"page-info\"> 共 "+this.TOTAL_PAGE_COUNT+"
		// 页 "+this.TOTAL_RECORDS_COUNT+" 条记录 </span>");

		if (CURRENT_PAGE_NO != 1) {// 如果当前页面不是第一页，则
			sbHtml.append("<a href=\"?pageno=" + 1 + "&" + this.PARAMS_STR + "\" title='首页'>| <</a>");// 首页
			sbHtml.append("<a href=\"?pageno=" + prepage + "&" + this.PARAMS_STR + "\">上一页</a>");// 上一页
		} else if (CURRENT_PAGE_NO == 1) {// 如果当前页面是第一页
			sbHtml.append("<a href=\"#\" title='首页'>| <</a>");// 首页
			sbHtml.append("<a href=\"#\">上一页</a>");// 上一页
		}

		for (long i = start; i <= end; i++) {

			String current_style = "";

			if (i == CURRENT_PAGE_NO)
				current_style = "class='current-page'";// 当前页面的样式

			sbHtml.append("<a href=\"?pageno=" + i + "&" + this.PARAMS_STR + "\" " + current_style + " >" + i + "</a>");
		}

		if (CURRENT_PAGE_NO != TOTAL_PAGE_COUNT) {// 如果当前页面不是最后一页，则
			sbHtml.append(
					"<a style=\"width: auto;\" href=\"?pageno=" + nextpage + "&" + this.PARAMS_STR + "\">下一页</a>");// 下一页
			sbHtml.append("<a href=\"?pageno=" + TOTAL_PAGE_COUNT + "&" + this.PARAMS_STR + "\" title='尾页'>> |</a>");// 尾页
		} else if (CURRENT_PAGE_NO == TOTAL_PAGE_COUNT) {// 如果当前页面是最后一页
			sbHtml.append("<a style=\"width: auto;\" href=\"#\">下一页</a>");// 下一页
			sbHtml.append("<a href=\"#\" title='尾页'>> |</a>");// 尾页
		}

		sbHtml.append("<span class=\"page-info\"> 共 " + this.TOTAL_PAGE_COUNT + " 页 " + this.TOTAL_RECORDS_COUNT
				+ " 条记录 </span>");
		sbHtml.append("</span>");

		// sbHtml.append("<script
		// language=javascript>//$(function(){;$(\".page-nav
		// a\").each(function(i){this.href=this.href;});});</script>");

		HTML_NAV = sbHtml.toString();

		return HTML_NAV;

	}

	/**
	 * 创建参数链接
	 * 
	 * @param request
	 * @return
	 */
	private String createParamsHref(HttpServletRequest request) {

		StringBuffer sb = new StringBuffer();

		Enumeration<String> enums = request.getParameterNames();

		while (enums.hasMoreElements()) {
			String key = enums.nextElement();

			if (key.equals("pageno"))
				continue;

			String value = request.getParameter(key);

			sb.append(key);
			sb.append("=");
			sb.append(value);

			if (enums.hasMoreElements())
				sb.append("&");
		}

		return sb.toString();

	}

	/**
	 * 得到当前页码
	 * 
	 * @return
	 */
	public long getCurrentPageNo() {
		return this.CURRENT_PAGE_NO;
	}

	/**
	 * 获得总的记录数
	 * 
	 * @return
	 */
	public long getTotalCount() {
		return this.TOTAL_RECORDS_COUNT;
	}
}